package com.hsd.whb.service.impl;

import com.hsd.whb.converter.MeetingConverter;
import com.hsd.whb.entity.*;
import com.hsd.whb.enums.DeviceStatusEnum;
import com.hsd.whb.enums.MeetingStatusEnum;
import com.hsd.whb.enums.ResultEnum;
import com.hsd.whb.exception.HwbException;
import com.hsd.whb.pojo.query.QueryMeeting;
import com.hsd.whb.properties.PersonProperties;
import com.hsd.whb.repository.*;
import com.hsd.whb.service.MeetingService;
import com.hsd.whb.pojo.output.MeetingVO;
import com.hsd.whb.utils.COSUtil;
import com.wangjiacai.hqlQuery.service.impl.BaseServiceImpl;
import com.wangjiacai.hqlQuery.util.HqlUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.ServletContext;
import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;

@Service
public class MeetingServiceImpl extends BaseServiceImpl implements MeetingService {


    @Autowired
    private ManagerRepository managerRepository;

    @Autowired
    private DeviceRepository deviceRepository;

    @Autowired
    private RecorderRepository recorderRepository;

    @Autowired
    private MeetingRepository meetingRepository;

    @Autowired
    private ParticipantsRepository participantsRepository;

    @Autowired
    private PersonProperties personProperties;


    @Override
    public long findFileRecordListTotalPages(String managerName, QueryMeeting queryMeeting) {
        if (!StringUtils.isEmpty(queryMeeting.getUsername())) {
            List<Integer> recorderIdList = recorderRepository.findIdByUsernameLike(queryMeeting.getUsername());
            if (recorderIdList.isEmpty()) return 0;
            queryMeeting.setRecorderIdList(recorderIdList);
        }
        Manager manager = managerRepository.findByUsername(managerName);
        queryMeeting.setManagerId(manager.getId());
        queryMeeting.setMeetingStatus(MeetingStatusEnum.ENDED.getCode());
        queryMeeting.setDeleted(0);
        return this.count(HqlUtil.getCountHql(queryMeeting), queryMeeting);
    }

    @Override
    public List<MeetingVO> findFileRecordList(Pageable pageable, String managerName, QueryMeeting queryMeeting) {
        if (!StringUtils.isEmpty(queryMeeting.getUsername())) {
            List<Integer> recorderIdList = recorderRepository.findIdByUsernameLike(queryMeeting.getUsername());
            if (recorderIdList.isEmpty()) return new ArrayList<>();
            queryMeeting.setRecorderIdList(recorderIdList);
        }
        Manager manager = managerRepository.findByUsername(managerName);
        queryMeeting.setManagerId(manager.getId());
        queryMeeting.setMeetingStatus(MeetingStatusEnum.ENDED.getCode());
        queryMeeting.setDeleted(0);
        List<Meeting> meetings = this.find(HqlUtil.getQueryHql(queryMeeting), queryMeeting, pageable, Meeting.class);
        List<MeetingVO> list = MeetingConverter.convertToMeetingVOList(meetings, recorderRepository);
        return list;
    }

    @Override
    public long findFileRecordListTotalPagesByRecorder(String recorderName, QueryMeeting queryMeeting) {
        Recorder recorder = recorderRepository.findByUsername(recorderName);
        queryMeeting.setRecorderId(recorder.getId());
        queryMeeting.setMeetingStatus(MeetingStatusEnum.ENDED.getCode());
        queryMeeting.setDeleted(0);
        return this.count(HqlUtil.getCountHql(queryMeeting), queryMeeting);
    }

    @Override
    public List<Meeting> findFileRecordListByRecorder(Pageable pageable, String recorderName, QueryMeeting queryMeeting) {
        Recorder recorder = recorderRepository.findByUsername(recorderName);
        queryMeeting.setRecorderId(recorder.getId());
        queryMeeting.setMeetingStatus(MeetingStatusEnum.ENDED.getCode());
        queryMeeting.setDeleted(0);
        return this.find(HqlUtil.getQueryHql(queryMeeting), queryMeeting, pageable, Meeting.class);
    }

    @Override
    public long findStayOpenFileRecordListTotalPagesByRecorder(String recorderName, QueryMeeting queryMeeting) {
        Recorder recorder = recorderRepository.findByUsername(recorderName);
        queryMeeting.setRecorderId(recorder.getId());
        queryMeeting.setMeetingStatus(MeetingStatusEnum.PENDING.getCode());
        queryMeeting.setDeleted(0);
        return this.count(HqlUtil.getCountHql(queryMeeting), queryMeeting);
    }

    @Override
    public List<MeetingVO> findStayOpenFileRecordListByRecorder(Pageable pageable, String recorderName, QueryMeeting queryMeeting) {
        Recorder recorder = recorderRepository.findByUsername(recorderName);
        queryMeeting.setRecorderId(recorder.getId());
        queryMeeting.setMeetingStatusNotIn(MeetingStatusEnum.ENDED.getCode());
        queryMeeting.setDeleted(0);
        List<Meeting> list = this.find(HqlUtil.getQueryHql(queryMeeting), queryMeeting, pageable, Meeting.class);
        return MeetingConverter.convertToMeetingVOList(list, recorderRepository);
    }

    @Override
    public Meeting findMeetingById(Integer id) {
        return meetingRepository.getOne(id);
    }

    @Override
    public Meeting save(Meeting meeting) {
        return meetingRepository.save(meeting);
    }

    @Override
    public void delete(Integer id) {
        Meeting meeting = meetingRepository.getOne(id);
        meetingRepository.save(meeting);
    }

    @Override
    public Meeting startMeeting(Integer meetingId, ServletContext servletContext, Integer language) {
        Meeting meeting = meetingRepository.getOne(meetingId);
        validStartMeeting(meeting);
        meeting.setMeetingStatus(MeetingStatusEnum.PROGRESSING.getCode());
        meeting.setStartTime(new Date());
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.HOUR_OF_DAY, meeting.getDuration());
        meeting.setEndTime(calendar.getTime());
        meeting = meetingRepository.save(meeting);
        return meeting;
    }

    @Override
    public Meeting endMeeting(Integer id, String username, ServletContext servletContext) {
        Meeting meeting = meetingRepository.getOne(id);
        validEndMeeting(meeting);
        meeting.setMeetingStatus(MeetingStatusEnum.ENDED.getCode());
        meeting.setRealEndTime(new Date());
        String filePath = personProperties.getImage() + "/meetingMaterals/" + id;
        File file = new File(filePath + "/" + id + ".pcm");
        CompletableFuture.runAsync(() -> {
            if (file.exists()) {
                COSUtil.uploadFile(file, file.getName());
                file.delete();
            }
        });
        return meetingRepository.save(meeting);
    }

    @Override
    public Meeting pauseMeeting(Integer id, ServletContext servletContext) {
        Meeting meeting = meetingRepository.getOne(id);
        validPauseMeeting(meeting);
        meeting.setMeetingStatus(MeetingStatusEnum.PAUSED.getCode());
        Device device = deviceRepository.getOne(meeting.getDeviceId());
        CompletableFuture.runAsync(() -> {
            // SocketUtil.endMeeting(servletContext, device.getAccessKey());
        });
        return meetingRepository.save(meeting);
    }

    @Override
    public Meeting restartMeeting(Integer id, ServletContext servletContext, Integer language) {
        Meeting meeting = meetingRepository.getOne(id);
        validRestartMeeting(meeting);
        meeting.setMeetingStatus(MeetingStatusEnum.PROGRESSING.getCode());
        Device device = deviceRepository.getOne(meeting.getDeviceId());
        // SocketUtil.startMeeting(servletContext, device.getAccessKey(), language);
        return meetingRepository.save(meeting);
    }

    @Override
    public void changeLanguage(Integer id, ServletContext servletContext, Integer language) {
        Meeting meeting = meetingRepository.getOne(id);
        Device device = deviceRepository.getOne(meeting.getDeviceId());
    }

    private void validStartMeeting(Meeting meeting) {
        List<Integer> status = new ArrayList<>();
        status.add(MeetingStatusEnum.PROGRESSING.getCode());
        status.add(MeetingStatusEnum.PAUSED.getCode());
        List<Meeting> meetingList = meetingRepository.findByDeviceIdAndMeetingStatusIn(meeting.getDeviceId(), status);
        if (meetingList.size() > 2) throw new HwbException(ResultEnum.DEVICE_NOW_USING);
    }

    private void validEndMeeting(Meeting meeting) {
        if (meeting.getMeetingStatus() != MeetingStatusEnum.PROGRESSING.getCode() &&
                meeting.getMeetingStatus() != MeetingStatusEnum.PAUSED.getCode()) {
            throw new HwbException(ResultEnum.MEETING_STATUS_ERROR);
        }
    }

    private void validPauseMeeting(Meeting meeting) {
        if (meeting.getMeetingStatus() != MeetingStatusEnum.PROGRESSING.getCode())
            throw new HwbException(ResultEnum.MEETING_STATUS_ERROR);
    }

    private void validRestartMeeting(Meeting meeting) {
        if (meeting.getMeetingStatus() != MeetingStatusEnum.PAUSED.getCode())
            throw new HwbException(ResultEnum.MEETING_STATUS_ERROR);
    }

    @Override
    public void updateSpeakUsername(Integer meetingId, String username, ServletContext servletContext) {
        Meeting meeting = meetingRepository.getOne(meetingId);
        if (meeting.getMeetingStatus() == MeetingStatusEnum.PENDING.getCode()) {
            throw new HwbException(ResultEnum.MEETING_NOT_START);
        }
        if (meeting.getMeetingStatus() == MeetingStatusEnum.ENDED.getCode()) {
            throw new HwbException(ResultEnum.MEETING_END);
        }
        Participants participants = participantsRepository.findByUsername(username);
        meeting.setSpeakerId(participants.getId());
        meetingRepository.save(meeting);
    }
}
